#include "SDL/SDL.h"
#include "SDL/SDL_thread.h"
#include "SDL/SDL_ttf.h"
#include "GL/gl.h"
#include <unistd.h>
#include <queue>

#include <libguile.h>

#include "texture.h"
#include "canvas.h"

int width = 640;
int height = 480;
bool fullscreen = false;

using namespace std;

int drawscreen(SDL_Surface* screen);
SCM videoinit(SCM w, SCM h, SCM fs);
int handle_event(SDL_Event event);
SCM quit(void);
void tick(unsigned int dt, unsigned int absolute);
SCM addimage(SCM name, SCM width, SCM height, SCM xsize, SCM ysize);
SCM addtext(SCM text, SCM x, SCM y, SCM width, SCM height);
SCM sizetext(SCM text);
SCM deltext(SCM text);
SCM move_image(SCM image, SCM x, SCM y);
SCM move_text(SCM image, SCM x, SCM y);

Canvas* canvas;
int running = 1;
SCM event_hook;
SCM tick_hook;
static scm_t_bits image_tag;
static scm_t_bits text_tag;

int main(int argc, char** argv) {
	scm_init_guile();
	scm_c_define_gsubr("videoinit", 3, 0, 0, (SCM(*)())videoinit);
	scm_c_define_gsubr("quit", 0, 0, 0, quit);
	scm_c_define_gsubr("size-text", 1, 0, 0, (SCM(*)())sizetext);
	scm_c_define_gsubr("addimage", 5, 0, 0, (SCM(*)())addimage);
	scm_c_define_gsubr("addtext", 5, 0, 0, (SCM(*)())addtext);
	scm_c_define_gsubr("deltext", 1, 0, 0, (SCM(*)())deltext);
	scm_c_define_gsubr("move-image", 3, 0, 0, (SCM(*)())move_image);
	scm_c_define_gsubr("move-text", 3, 0, 0, (SCM(*)())move_text);

	event_hook = scm_make_hook(scm_from_int(1));
	scm_c_define("event-hook", event_hook);
	tick_hook = scm_make_hook(scm_from_int(2));
	scm_c_define("tick-hook", tick_hook);

	image_tag = scm_make_smob_type("image", sizeof(StaticImage));
	text_tag = scm_make_smob_type("text", sizeof(StaticText));

	SDL_Init(SDL_INIT_VIDEO);
	TTF_Init();
	initTexture();
	canvas = new Canvas();
	int sdl_flags = SDL_OPENGL;
	scm_c_primitive_load("main.scm");
	if(fullscreen) sdl_flags |= SDL_FULLSCREEN;
	
	printf("Width: %d, Height %d, Fullscreen: %d\n", width, height, fullscreen);

	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	SDL_Surface* screen = SDL_SetVideoMode(width, height, 16, sdl_flags);
	canvas->SetSize(0, 0, width, height);

	glClearColor(0, 0, 0, 0);
	glMatrixMode(GL_PROJECTION_MATRIX);
	glLoadIdentity();
	glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
	Uint32 lastframe = SDL_GetTicks();
	
	while(running) {
		SDL_Event event;
		while(SDL_PollEvent(&event)) {
			handle_event(event);
		}
		Uint32 now = SDL_GetTicks();
		tick(now - lastframe, now);
		lastframe = now;
		drawscreen(screen);
		SDL_Delay(1);
	}
	printf("Quitting\n");
	finiTexture();
	SDL_Quit();

	return 0;
}

int drawscreen(SDL_Surface* screen) {
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW_MATRIX);
	glLoadIdentity();
	glViewport(0, 0, width, height);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	glBegin(GL_LINES);
	glVertex2f(0.0, -0.5);
	glVertex2f(0.0, 0.5);
	
	glVertex2f(-0.5, 0.0);
	glVertex2f(0.5, 0.0);
	glEnd();
	
	canvas->Render();
	SDL_GL_SwapBuffers();
}

SCM videoinit(SCM w, SCM h, SCM fs) {
	width = scm_to_int(w);
	height = scm_to_int(h);
	fullscreen = scm_to_bool(fs);
	return SCM_BOOL_T;
}

int handle_event(SDL_Event event) {
	SCM arglist;
	if(event.type == SDL_KEYDOWN) {
		char sym = event.key.keysym.sym;
		arglist = scm_list_2(scm_from_locale_symbol("keydown"), scm_from_char(sym));
	} else if(event.type == SDL_KEYUP) {
		char sym = event.key.keysym.sym;
		arglist = scm_list_2(scm_from_locale_symbol("keyup"), scm_from_char(sym));
	} else if(event.type == SDL_MOUSEBUTTONDOWN) {
		arglist = scm_list_4(scm_from_locale_symbol("buttondown"),
				     scm_from_int(event.button.button),
				     scm_from_int(event.button.x),
				     scm_from_int(height - event.button.y));
	} else if(event.type == SDL_QUIT) {
		arglist = scm_list_1(scm_from_locale_symbol("quit"));
	} else return 0;

	scm_run_hook(event_hook, scm_list_1(arglist));
	return 0;
}

SCM quit(void) {
	running = false;
	return SCM_UNSPECIFIED;
}

void tick(unsigned int dt, unsigned int absolute) {
	scm_run_hook(tick_hook, scm_list_2(scm_from_double((float)dt/1000.0), 
					   scm_from_double((float)absolute/1000.0)));
}

SCM addimage(SCM name, SCM x, SCM y, SCM xsize, SCM ysize) {
	SCM image;
	StaticImage* ident = canvas->AddImage(scm_to_int(x),
					      scm_to_int(y),
					      scm_to_int(xsize),
					      scm_to_int(ysize),
					      scm_to_locale_string(name));
	SCM_NEWSMOB(image, image_tag, ident);
	return image;
}

SCM addtext(SCM text, SCM x, SCM y, SCM width, SCM height) {
	SCM ret;
	StaticText* ident = canvas->AddText(scm_to_int(x),
					    scm_to_int(y),
					    (int)scm_to_double(width),
					    (int)scm_to_double(height),
					    scm_to_locale_string(text));
	SCM_NEWSMOB(ret, text_tag, ident);
	return ret;
}

SCM sizetext(SCM text) {
	int x, y;
	canvas->SizeText(scm_to_locale_string(text), &x, &y);
	return scm_list_2(scm_from_int(x), scm_from_int(y));
}

SCM deltext(SCM text) {
	scm_assert_smob_type(text_tag, text);
	canvas->DelText((StaticText*) SCM_SMOB_DATA(text));
}

SCM move_image(SCM image, SCM x, SCM y) {
	scm_assert_smob_type(image_tag, image);
	
	StaticImage* im = (StaticImage*) SCM_SMOB_DATA(image);
	float x1 = scm_to_double(x);
	float y1 = scm_to_double(y);
	
	return scm_from_bool(!canvas->Move(im, x1, y1));
}

SCM move_text(SCM image, SCM x, SCM y) {
	scm_assert_smob_type(text_tag, image);
	
	StaticText* im = (StaticText*) SCM_SMOB_DATA(image);
	float x1 = scm_to_double(x);
	float y1 = scm_to_double(y);
	
	return scm_from_bool(!canvas->Move(im, x1, y1));
}
